@tool
extends MeshInstance3D
class_name BoxFrame

@export var material : ShaderMaterial;

const VSIZE_LINE = 4
const INXSIZE_LINE = 6
const VSIZE_BOX = VSIZE_LINE * 12
const INXSIZE_BOX = INXSIZE_LINE * 12

var color : Color
var mat: Material

enum LINE_MODE
{
	LM_ENDPOINTS,
	LM_WAYPOINTS,	
}

func _ready():
	#mat = mesh.surface_get_material(0).duplicate(true)
	mat = material.duplicate(true)
	pass

func clear_surfaces():
	mesh.clear_surfaces()
	pass

func draw_box_list( cl: PackedVector3Array, hs: PackedVector3Array, width: float = 1.0 ):
	var v: PackedVector3Array = []
	var n: PackedVector3Array = []
	var inx: PackedInt32Array = []
	v.resize( VSIZE_BOX * cl.size() )
	n.resize( VSIZE_BOX * cl.size() )
	inx.resize( INXSIZE_BOX * cl.size() )
	
	for i in cl.size():
		push_a_box( cl[i], hs[i] * 0.5, i * VSIZE_BOX, v, n, inx )
		pass
	
	var meshInfo : Array = []
	meshInfo.resize(13)
	meshInfo[Mesh.ARRAY_VERTEX] = v
	meshInfo[Mesh.ARRAY_NORMAL] = n
	meshInfo[Mesh.ARRAY_INDEX] = inx
	
	var amesh : ArrayMesh = mesh
	amesh.clear_surfaces()
	mat.set_shader_parameter("width", width)
	mat.set_shader_parameter("color", color)
	amesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, meshInfo)
	amesh.surface_set_material(0, mat)
	pass
	
func draw_a_box( c: Vector3, hs: Vector3, width: float = 1.0 ):
	var v: PackedVector3Array = []
	var n: PackedVector3Array = []
	var inx: PackedInt32Array = []
	v.resize( VSIZE_BOX )
	n.resize( VSIZE_BOX )
	inx.resize( INXSIZE_BOX )
	
	push_a_box( c, hs, 0, v, n, inx )
	
	var meshInfo : Array = []
	meshInfo.resize(13)
	meshInfo[Mesh.ARRAY_VERTEX] = v
	meshInfo[Mesh.ARRAY_NORMAL] = n
	meshInfo[Mesh.ARRAY_INDEX] = inx
	
	var amesh : ArrayMesh = mesh
	amesh.clear_surfaces()
	mat.set_shader_parameter("width", width)
	mat.set_shader_parameter("color", color)
	amesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, meshInfo)
	amesh.surface_set_material(0, mat)
	pass

func draw_line_list( pts: PackedVector3Array, mode: LINE_MODE,  width:float = 1.0 ):
	var v: PackedVector3Array = []
	var n: PackedVector3Array = []
	var inx: PackedInt32Array = []
	
	var bSize = 0
	if mode == LINE_MODE.LM_WAYPOINTS:
		bSize = pts.size() - 1
	else:
		bSize = pts.size() / 2
		
	v.resize( VSIZE_LINE * bSize )
	n.resize( VSIZE_LINE * bSize )
	inx.resize( INXSIZE_LINE * bSize )
	
	if mode == LINE_MODE.LM_WAYPOINTS:
		for i in range(0, pts.size() - 1):
			push_a_line( pts[i], pts[i + 1], VSIZE_LINE * i, v, n, inx  )
	else:
		for i in range(0, pts.size(), 2):
			push_a_line( pts[i], pts[i + 1], VSIZE_LINE * i / 2, v, n, inx )

	var meshInfo : Array = []
	meshInfo.resize(13)
	meshInfo[Mesh.ARRAY_VERTEX] = v
	meshInfo[Mesh.ARRAY_NORMAL] = n
	meshInfo[Mesh.ARRAY_INDEX] = inx
	
	var amesh : ArrayMesh = mesh
	amesh.clear_surfaces()
	mat.set_shader_parameter("width", width)
	mat.set_shader_parameter("color", color)
	amesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, meshInfo)
	amesh.surface_set_material(0, mat)
	pass

func draw_a_line( p1: Vector3, p2: Vector3, width: float = 1.0 ):
	var v: PackedVector3Array = []
	var n: PackedVector3Array = []
	var inx: PackedInt32Array = []
	v.resize(VSIZE_LINE)
	n.resize(VSIZE_LINE)
	inx.resize(INXSIZE_LINE)
	push_a_line( p1, p2, 0, v, n, inx )
	
	var meshInfo : Array = []
	meshInfo.resize(13)
	meshInfo[Mesh.ARRAY_VERTEX] = v
	meshInfo[Mesh.ARRAY_NORMAL] = n
	meshInfo[Mesh.ARRAY_INDEX] = inx
	
	var amesh : ArrayMesh = mesh
	amesh.clear_surfaces()
	mat.set_shader_parameter("width", width)
	mat.set_shader_parameter("color", color)
	amesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, meshInfo)
	amesh.surface_set_material(0, mat)
	pass

func push_a_box( c: Vector3, hs: Vector3, offset: int,
	v:PackedVector3Array, n:PackedVector3Array, inx: PackedInt32Array ):
	var vs : PackedVector3Array = \
	[
		c + Vector3( hs.x, hs.y, hs.z ),
		c + Vector3( hs.x, -hs.y, hs.z ),
		c + Vector3( -hs.x, -hs.y, hs.z ),
		c + Vector3( -hs.x, hs.y, hs.z ),
		c + Vector3( hs.x, hs.y, -hs.z ),
		c + Vector3( hs.x, -hs.y, -hs.z ),
		c + Vector3( -hs.x, -hs.y, -hs.z ),
		c + Vector3( -hs.x, hs.y, -hs.z ),
	]
	
	push_a_line( vs[0], vs[1], offset, v, n, inx )
	push_a_line( vs[1], vs[2], offset + VSIZE_LINE, v, n, inx )
	push_a_line( vs[2], vs[3], offset + VSIZE_LINE * 2, v, n, inx )
	push_a_line( vs[3], vs[0], offset + VSIZE_LINE * 3, v, n, inx )
	
	push_a_line( vs[0], vs[4], offset + VSIZE_LINE * 4, v, n, inx )
	push_a_line( vs[1], vs[5], offset + VSIZE_LINE * 5, v, n, inx )
	push_a_line( vs[2], vs[6], offset + VSIZE_LINE * 6, v, n, inx )
	push_a_line( vs[3], vs[7], offset + VSIZE_LINE * 7, v, n, inx )
	
	push_a_line( vs[4], vs[5], offset + VSIZE_LINE * 8, v, n, inx )
	push_a_line( vs[5], vs[6], offset + VSIZE_LINE * 9, v, n, inx )
	push_a_line( vs[6], vs[7], offset + VSIZE_LINE * 10, v, n, inx )
	push_a_line( vs[7], vs[4], offset + VSIZE_LINE * 11, v, n, inx )
	
	pass

func push_a_line( p1: Vector3, p2: Vector3, offset: int,
	v:PackedVector3Array, n:PackedVector3Array, inx: PackedInt32Array ):
	var d2: Vector3 = p1 - p2;
	var d1: Vector3 = p2 - p1;
	v[offset] = p1
	v[offset + 1] = p2
	v[offset + 2] = p2
	v[offset + 3] = p1
	n[offset] = d1
	n[offset + 1] = d1
	n[offset + 2] = d2
	n[offset + 3] = d2
	
	var iOffset = offset / 4 * 6
	inx[iOffset] = offset
	inx[iOffset + 1] = offset + 1
	inx[iOffset + 2] = offset + 2
	
	inx[iOffset + 3] = offset
	inx[iOffset + 4] = offset + 2
	inx[iOffset + 5] = offset + 3
	pass
